package com.sugar.psych.assessment.module.business.service.psychquestion;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sugar.psych.assessment.framework.common.util.json.JsonUtils;
import com.sugar.psych.assessment.module.business.dal.dataobject.psychquestionbank.PsychQuestionBankDO;
import com.sugar.psych.assessment.module.business.dal.dataobject.school.SchoolDO;
import com.sugar.psych.assessment.module.business.dal.dataobject.user.UserDO;
import com.sugar.psych.assessment.module.business.dal.mysql.psychquestionbank.PsychQuestionBankMapper;
import com.sugar.psych.assessment.module.infra.controller.app.file.vo.AppFileUploadReqVO;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import com.sugar.psych.assessment.module.business.controller.admin.psychquestion.vo.*;
import com.sugar.psych.assessment.module.business.dal.dataobject.psychquestion.PsychQuestionDO;
import com.sugar.psych.assessment.framework.common.pojo.PageResult;
import com.sugar.psych.assessment.framework.common.pojo.PageParam;
import com.sugar.psych.assessment.framework.common.util.object.BeanUtils;

import com.sugar.psych.assessment.module.business.dal.mysql.psychquestion.PsychQuestionMapper;

import static com.sugar.psych.assessment.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.psych.assessment.framework.common.util.collection.CollectionUtils.convertList;
import static com.sugar.psych.assessment.framework.common.util.collection.CollectionUtils.diffList;
import static com.sugar.psych.assessment.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static com.sugar.psych.assessment.module.business.enums.ErrorCodeConstants.*;

/**
 * 心理测评题目 Service 实现类
 *
 * @author Ysugar
 */
@Service
@Validated
public class PsychQuestionServiceImpl implements PsychQuestionService {

    @Resource
    private PsychQuestionBankMapper psychQuestionBankMapper;
    @Resource
    private PsychQuestionMapper psychQuestionMapper;

    @Override
    public Long createPsychQuestion(PsychQuestionSaveReqVO createReqVO) {
        createReqVO.setQuestionType(false);
        // 插入
        PsychQuestionDO psychQuestion = BeanUtils.toBean(createReqVO, PsychQuestionDO.class);
        psychQuestionMapper.insert(psychQuestion);
        // 返回
        return psychQuestion.getId();
    }

    @Override
    public void updatePsychQuestion(PsychQuestionSaveReqVO updateReqVO) {
        updateReqVO.setQuestionType(false);
        // 校验存在
        validatePsychQuestionExists(updateReqVO.getId());
        // 更新
        PsychQuestionDO updateObj = BeanUtils.toBean(updateReqVO, PsychQuestionDO.class);
        psychQuestionMapper.updateById(updateObj);
    }

    @Override
    public void deletePsychQuestion(Long id) {
        // 校验存在
        validatePsychQuestionExists(id);
        // 删除
        psychQuestionMapper.deleteById(id);
    }

    @Override
    public void deletePsychQuestionListByIds(List<Long> ids) {
        // 校验存在
        validatePsychQuestionExists(ids);
        // 删除
        psychQuestionMapper.deleteByIds(ids);
    }

    private void validatePsychQuestionExists(List<Long> ids) {
        List<PsychQuestionDO> list = psychQuestionMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(PSYCH_QUESTION_NOT_EXISTS);
        }
    }

    private void validatePsychQuestionExists(Long id) {
        if (psychQuestionMapper.selectById(id) == null) {
            throw exception(PSYCH_QUESTION_NOT_EXISTS);
        }
    }

    @Override
    public PsychQuestionDO getPsychQuestion(Long id) {
        return psychQuestionMapper.selectById(id);
    }

    @Override
    public PageResult<PsychQuestionRespVO> getPsychQuestionPage(PsychQuestionPageReqVO pageReqVO) {
        return psychQuestionMapper.selectPage(pageReqVO);
    }

    @Override
    public void writeExcel(PsychQuestionPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        // 自定义头部标题
        List<String> headList1 = CollUtil.newArrayList("序号", "题库", "题目", "选项信息", "", "", "排序", "创建时间");
        List<String> headList2 = CollUtil.newArrayList("", "", "", "选项", "内容", "分值", "", "");

        ExcelWriter writer = ExcelUtil.getWriter(/*"E:/test/writeBeanTest.xlsx"*/);

        // 获取样式
        StyleSet style = writer.getStyleSet();
        Font headFont = writer.createFont();
        headFont.setBold(true);
        headFont.setFontHeightInPoints((short) 16);
        //重点，设置中文字体
        headFont.setFontName("楷体");
        style.setWrapText();
        // 设置头部标题字体与背景色
        style.getHeadCellStyle().setFont(headFont);
        style.getHeadCellStyle().setFillForegroundColor(IndexedColors.WHITE.getIndex());

        // 写入头部标题
        writer.writeHeadRow(headList1);
        writer.writeHeadRow(headList2);

        // 获取所有题库
        List<PsychQuestionRespVO> questions = this.getPsychQuestionPage(pageReqVO).getList();
        // 根据题库编号分组
        Map<Long, List<PsychQuestionRespVO>> dataListMapGroupByBankId = questions.stream().collect(Collectors.groupingBy(PsychQuestionRespVO::getBankId));
        Set<Long> bankIds = dataListMapGroupByBankId.keySet();
        int bankRowNum = 2;
        int rowNum = 2;
        for (Long bankId : bankIds) {
            List<PsychQuestionRespVO> dataList = dataListMapGroupByBankId.get(bankId);
            int size = dataList.size();
            for (int i = 0; i < size; i++) {
                PsychQuestionRespVO data = dataList.get(i);

                String createTimeStr = data.getCreateTime().format(DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));

                List<PsychQuestionDO.Option> optionList = data.getOptionList();
                int optionSize = optionList.size();
                int idx = (i + 1);
                for (PsychQuestionDO.Option option : optionList) {
                    // 构建该行每个单元格内容
                    ArrayList<String> rowPlanContents = CollUtil.newArrayList("" + idx, data.getBankTitle(), data.getTitle()
                            , option.getSelTitle(), option.getContent(), String.valueOf(option.getScore()),
                            String.valueOf(data.getSort()), createTimeStr);
                    writer.writeRow(rowPlanContents);
                }

                int lastRow = rowNum + optionSize - 1;

                writer.merge(rowNum, lastRow, 0, 0, idx, false);
                /*writer.merge(rowNum, lastRow, 1, 1, data.getBankTitle(), false);*/
                writer.merge(rowNum, lastRow, 2, 2, data.getTitle(), false);
                writer.merge(rowNum, lastRow, 6, 6, data.getSort(), false);
                writer.merge(rowNum, lastRow, 7, 7, createTimeStr, false);
                rowNum += optionSize;
            }

            writer.merge(bankRowNum, rowNum - 1, 1, 1, dataList.get(0).getBankTitle(), false);
            bankRowNum = rowNum;
        }

        // 合并标题单元格
        writer.merge(0, 0, 3, 5, "选项信息", true);
        writer.merge(0, 1, 0, 0, "序号", true);
        writer.merge(0, 1, 1, 1, "题库", true);
        writer.merge(0, 1, 2, 2, "题目", true);
        writer.merge(0, 1, 6, 6, "排序", true);
        writer.merge(0, 1, 7, 7, "创建时间", true);

        writer.setOnlyAlias(true);
        writer.autoSizeColumnAll();

        writer.setColumnWidth(1, 20);
        writer.setColumnWidth(2, 33);
        writer.setColumnWidth(4, 25);
        writer.setColumnWidth(7, 25);

        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        // test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=题目信息.xls");
        ServletOutputStream out = response.getOutputStream();

        writer.flush(out, true);
        // 关闭writer，释放内存
        writer.close();
        // 此处记得关闭输出Servlet流
        IoUtil.close(out);
    }

    @Override
    public void importExcel(AppFileUploadReqVO reqVO) throws IOException {
        EasyExcel.read(reqVO.getFile().getInputStream(), new ReadListener<Map<Integer, String>>() {
            @Override
            public void invoke(Map<Integer, String> data, AnalysisContext context) {
                System.out.println(JsonUtils.toJsonString(data));
                // 查询题库是否存在
                PsychQuestionBankDO bank = psychQuestionBankMapper.selectById(data.get(0));
                if (null != bank) {
                    List<PsychQuestionDO.Option> optionList = new ArrayList<>();
                    PsychQuestionDO question = new PsychQuestionDO();
                    question.setBankId(bank.getId())
                            .setQuestionType(false)
                            .setTitle(data.get(1))
                            .setSort(Integer.parseInt(data.get(2)))
                            .setOptionList(optionList);

                    Set<Integer> keySet = data.keySet();
                    int optionSize = keySet.size();
                    for (int i = 3; i < optionSize; i++) {
                        if (data.get(i) == null || data.get(i + 1) == null || data.get(i + 2) == null)
                            break;
                        PsychQuestionDO.Option option = new PsychQuestionDO.Option();
                        option.setSelTitle(data.get(i)).setContent(data.get(++i)).setScore(Integer.parseInt(data.get(++i)));
                        optionList.add(option);
                    }

                    // 插入题目
                    if (CollUtil.isNotEmpty(optionList))
                        psychQuestionMapper.insert(question);
                }
            }

            // 读取完毕
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
            }
        }).sheet().doRead();
    }

}